using System;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Xml.Serialization;
using Microsoft.Xna.Framework;

namespace Game500.ClientServerCommon.Src
{
  public class BaseMapManager
  {
    private const string ThumbnailLookupDirectory = "..\\Media";
    private HashSet<Guid> myAllowedMaps;
    private Dictionary<Guid, Map> myMaps;

    public BaseMapManager(string fileName = "Resources\\Maps.xml")
    {
      if (!File.Exists(fileName)) CreateBaseFile(fileName);

      LoadMaps(fileName);
    }

    public Guid DefaultMapGuid
    {
      get { return myMaps.First().Value.MapId; }
    }

    public Map DefaultMap
    {
      get { return myMaps.First().Value; }
    }

    private void CreateBaseFile(string fileName)
    {
      var serializer = new XmlSerializer(typeof (List<Map>));
      using (var writer = new StreamWriter(fileName))
      {
        var background = new Shape {Height = 1200, TextureName = "cloudsBig.jpg", Width = 1600, Position = new Vector3(0, -78, 1)};
        var obstacle = new Shape {Height = 150, Width = 300, Position = new Vector3(650, 0, 0.9f), TextureName = "house.png"};
        var map = new Map {MapId = new Guid("fe3e8f7a-dc77-410a-a18c-d4f1162b461f"), Name = "Default map", Thumbnail = "cloudsBig.jpg", YOffset = -78, MapHeight = 1200, MapWidth = 1600};
        map.Objects.Add(background);
        map.Objects.Add(obstacle);
        var maps = new List<Map> {map};
        serializer.Serialize(writer, maps);
      }
    }

    public void AllowMaps(IEnumerable<Guid> allowedMaps)
    {
      if (allowedMaps == null)
      {
        myAllowedMaps = null;
        return;
      }

      myAllowedMaps = new HashSet<Guid>(allowedMaps);
    }

    public Map GetMap(Guid id)
    {
      // TODO: caching last map may be useful
      if (myAllowedMaps == null || myAllowedMaps.Contains(id))
      {
        Map result;
        if (myMaps.TryGetValue(id, out result)) return result;
        return null;
      }
      return null;
    }

    public IEnumerable<Guid> GetAvailableMapIds()
    {
      if (myAllowedMaps == null) return myMaps.Keys;
      return myMaps.Keys.Where(x => myAllowedMaps.Contains(x));
    }

    private void LoadMaps(string fileName)
    {
      var serializer = new XmlSerializer(typeof (List<Map>));
      using (var reader = new StreamReader(fileName))
      {
        var maps = (List<Map>)serializer.Deserialize(reader);
        myMaps = maps.ToDictionary(x => x.MapId);
      }
    }

    public Image GetThumbnail(Guid mapId)
    {
      Map map = GetMapNotNull(mapId);
      string path = Path.Combine(ThumbnailLookupDirectory, map.Thumbnail);
      path = Path.GetFullPath(path);
      return Image.FromFile(path);
    }

    public string GetMapName(Guid mapId)
    {
      Map map = GetMapNotNull(mapId);
      return map.Name;
    }

    public Map GetMapNotNull(Guid mapId)
    {
      Map map = GetMap(mapId);
      if (map == null) throw new Exception("Map not found: " + mapId);
      return map;
    }

    public int GetMapWidth(Guid mapId)
    {
      Map map = GetMapNotNull(mapId);
      return map.MapWidth;
    }

    public int GetMapHeight(Guid mapId)
    {
      Map map = GetMapNotNull(mapId);
      return map.MapHeight;
    }

    public bool AcceptsMap(Guid mapId)
    {
      return GetMap(mapId) != null;
    }

    public IEnumerable<Map> GetAvailableMaps()
    {
      return myMaps.Values;
    }
  }
}